package love.unknown.fruit.dao.base;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public abstract class BaseDAO <T>{
    public final String DRIVER = "com.mysql.jdbc.Driver";
    public final String URL = "jdbc:mysql://192.168.108.129:3306/fruitdb?useSSL=false&characterEncoding=utf-8";
    public final String USER = "root";
    public final String PWD = "123456";

    protected Connection conn;
    protected ResultSet rs ;
    protected PreparedStatement ps;

    private Class entityClass;

    public BaseDAO(){
        Type genericType = getClass().getGenericSuperclass();   //getClass是子类对象调用的 当前是new FruitDAOImpl
        Type[] actualTypeArguments = ((ParameterizedType) genericType).getActualTypeArguments();
        Type actualType = actualTypeArguments[0];
        try {
            entityClass = Class.forName(actualType.getTypeName());
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

    }
    protected Connection getConn() {
        //1.加载驱动
        try {
            Class.forName(DRIVER);
            //2.通过驱动管理器获取连接对象
            return DriverManager.getConnection(URL, USER, PWD);
        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    protected void close(ResultSet rs, PreparedStatement ps, Connection conn) {
        try {
            if (rs != null)
                rs.close();
            if (ps != null)
                ps.close();
            if (conn != null && !conn.isClosed())
                conn.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    protected void setParams(PreparedStatement ps,Object ...params) throws SQLException {
        if (params!=null&&params.length>0){
            for (int i = 0; i < params.length; i++) {
                ps.setObject(i+1,params[i]);
            }
        }

    }

    //执行更新,返回影响行数
    protected int executeUpdate(String sql,Object ...params) {
        boolean insertFlag = false;
        insertFlag = sql.trim().toUpperCase().startsWith("INSERT");
        try {
            conn = getConn();
            if (insertFlag){
                ps = conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
            }else {
                ps = conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
            }
            setParams(ps,params);
            int count = ps.executeUpdate();
            rs = ps.getGeneratedKeys();
            if (rs.next())
                return ((Long)rs.getLong(1)).intValue();//获取自增列的值
            return count;
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            close(rs,ps,conn);
        }
        return 0;
    }

    //通过反射技术给obj对象的属性赋值
    private void setValue(Object obj,String prop,Object value){
        Class<?> clazz = obj.getClass();
        Field field = null;
        try {
            field = clazz.getDeclaredField(prop);
            field.setAccessible(true);
            field.set(obj,value);

        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }

    }

    //执行查询,返回单个
    protected T load(String sql,Object ...params){
        try {
            conn = getConn();
            ps = conn.prepareStatement(sql);
            setParams(ps,params);
            rs = ps.executeQuery();
            ResultSetMetaData rsmd = rs.getMetaData();
            int columnCount = rsmd.getColumnCount();

            if (rs.next()) {
                T entity = (T) entityClass.newInstance();
                for (int i = 0; i < columnCount; i++) {
                    String columnLabel = rsmd.getColumnLabel(i + 1);
                    Object columnValue = rs.getObject(i + 1);
                    setValue(entity,columnLabel,columnValue);
                }
                return entity;
            }
        } catch (SQLException | InstantiationException | IllegalAccessException e) {
            throw new RuntimeException(e);
        } finally {
            close(rs, ps, conn);
        }
        return null;
    }
    //执行查询,返回List
    protected List<T> excuteQuery(String sql,Object ...params){
        List<T> list = new ArrayList<>();
        try {
            conn = getConn();
            ps = conn.prepareStatement(sql);
            setParams(ps,params);
            rs = ps.executeQuery();
            ResultSetMetaData rsmd = rs.getMetaData();
            int columnCount = rsmd.getColumnCount();

            while (rs.next()) {
                T entity = (T) entityClass.newInstance();
                for (int i = 0; i < columnCount; i++) {
                    String columnLabel = rsmd.getColumnLabel(i + 1);
                    Object columnValue = rs.getObject(i + 1);
                    setValue(entity,columnLabel,columnValue);
                }
                list.add(entity);
            }
        } catch (SQLException | InstantiationException | IllegalAccessException e) {
            throw new RuntimeException(e);
        } finally {
            close(rs, ps, conn);
        }
        return list;
    }

    //执行复杂查询,返回例如统计结果
    protected Object[] executeComplexQuery(String sql , Object... params){
        try {
            conn = getConn() ;
            ps = conn.prepareStatement(sql);
            setParams(ps,params);
            rs = ps.executeQuery();

            //通过rs可以获取结果集的元数据
            //元数据：描述结果集数据的数据 , 简单讲，就是这个结果集有哪些列，什么类型等等

            ResultSetMetaData rsmd = rs.getMetaData();
            //获取结果集的列数
            int columnCount = rsmd.getColumnCount();
            Object[] columnValueArr = new Object[columnCount];
            //6.解析rs
            if(rs.next()){
                for(int i = 0 ; i<columnCount;i++){
                    Object columnValue = rs.getObject(i+1);     //33    苹果      5
                    columnValueArr[i]=columnValue;
                }
                return columnValueArr ;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            close(rs,ps,conn);
        }
        return null ;
    }
}
